package data;

import org.apache.commons.lang3.ArrayUtils;
import util.ImportFile;
import util.RandomGen;

import java.util.Arrays;
import java.util.List;

/*
* 基因类（可以看做一个个小分区）
* order:序号，和流水号对应
* ensembl_gene_id:???
* associated_gene_name:基因名
* start:起始位点
* end:终止位点
* chromosome:这段基因属于哪个染色体
* G_Detail:genes的一些细节（包含大分区的始末位点）
*
* */
public class Genes {
    private int[] order;
    private String[] ensembl_gene_id;
    private String[] associated_gene_name;
    private int[] start;
    private int[] end;
    private String[] chromosome;
    private G_Detail g_detail;

    public int[] getOrder() {
        return order;
    }

    public void setOrder(int[] order) {
        this.order = order;
    }

    public String[] getEnsembl_gene_id() {
        return ensembl_gene_id;
    }

    public void setEnsembl_gene_id(String[] ensembl_gene_id) {
        this.ensembl_gene_id = ensembl_gene_id;
    }

    public String[] getAssociated_gene_name() {
        return associated_gene_name;
    }

    public void setAssociated_gene_name(String[] associated_gene_name) {
        this.associated_gene_name = associated_gene_name;
    }

    public int[] getStart() {
        return start;
    }

    public void setStart(int[] start) {
        this.start = start;
    }

    public int[] getEnd() {
        return end;
    }

    public void setEnd(int[] end) {
        this.end = end;
    }

    public String[] getChromosome() {
        return chromosome;
    }

    public void setChromosome(String[] chromosome) {
        this.chromosome = chromosome;
    }

    public G_Detail getG_detail() {
        return g_detail;
    }

    public void setG_detail(G_Detail g_detail) {
        this.g_detail = g_detail;
    }

    //genes的一些细节
    public static class G_Detail{
        int chromosomeNumber;
        int posMin;  //用来记录模拟数据中的位点选择区间（只针对仿真数据，对真实数据无用）
        int posMax;
        int[] start_bigZone;//大分区的起始位点集
        int[] end_bigZone;//大分区的终止位点集
        String[] chromosome_bigZone;
        String[] name_bigZone;
    }



    /*
     * 真实数据(将文件取出来的值赋值)
     * filePath:文件路径
     * symbol:分割符
     * col_title:是否具有列名
     *
     * */
    public void assign(String filePath, String symbol, boolean col_title){
        //list:提取的数据（每一个元素是一行数据，未被分割）
        List list = ImportFile.readFile(filePath);

        int row_length = col_title?list.size()-1:list.size();
        int column_length = list.get(0).toString().split(symbol).length;
        String[] lineData = new String[column_length];

        ensembl_gene_id = new String[row_length];
        associated_gene_name = new String[row_length];
        start = new int[row_length];
        end = new int[row_length];
        chromosome = new String[row_length];

        for (int i= 0 ;i<row_length;i++){
            if(col_title==false){
                lineData = list.get(i).toString().split(symbol);
            }else {
                lineData = list.get(i+1).toString().split(symbol);
            }
            int j = 0;
            this.ensembl_gene_id[i] = lineData[j++];
            this.associated_gene_name[i] = lineData[j++];
            this.start[i] = Integer.valueOf(lineData[j++]);
            this.end[i] = Integer.valueOf(lineData[j++]);
            this.chromosome[i] = lineData[j];
        }
    }


    /*
     * 模拟数据（每种染色体的基因小分区数量随机，小分区长度以上属染色体长度随机）
     * basicNumber:基础流水号
     * chromosomeNumber:染色体数目
     * totalNumber:基因总数
     * posMin/posMax:位点范围(左闭右开，左边0的时候则是开)
     *
     * */
    public void simulateRandomly(String basicNumber,int chromosomeNumber,int totalNumber,int posMin,int posMax){
        String serial_number; //流水号
        order = new int[totalNumber];
        ensembl_gene_id = new String[totalNumber];
        associated_gene_name = new String[totalNumber];
        start = new int[totalNumber];
        end = new int[totalNumber];
        chromosome = new String[totalNumber];
        g_detail = new G_Detail();


        if (chromosomeNumber<1 && chromosomeNumber >23){
            System.out.println("染色体数目最多为23对，最少为1对");
        }

        //赋予totalNumber个流水号
        for (int i=0;i<totalNumber;i++){
            ensembl_gene_id[i] = "NA";
            order[i] = i+1;
            serial_number = String.valueOf(i+1);
            serial_number = basicNumber.substring(0, basicNumber.length()-serial_number.length())+serial_number; //将序号和流水基础号组合
            associated_gene_name[i] = serial_number;
        }

        //赋予染色体，某个种类的染色体个数随机
        g_detail.chromosomeNumber = chromosomeNumber;

        int[] genesPerChrom = new int[chromosomeNumber];
        int genesMaxNumber = 2*totalNumber/chromosomeNumber;  //基因上限，避免死循环
        do {
            genesPerChrom = RandomGen.randomSpliting(chromosomeNumber,totalNumber,genesMaxNumber);
        }while (ArrayUtils.contains(genesPerChrom,1) || ArrayUtils.contains(genesPerChrom,2)); //保证每种染色体的标记个数不至于太少


        int number = 0;
        for (int i=0;i<chromosomeNumber;i++){
            for (int j=0;j<genesPerChrom[i];j++){
                if (i!=22){
                    chromosome[number++] = String.valueOf(i+1);
                }else {
                    chromosome[number++] = "X";
                }
            }
        }

        //分配大分区的始末位点，染色体，这里用等分的方式
        g_detail.posMin = posMin;
        g_detail.posMax = posMax;
        g_detail.start_bigZone = new int[chromosomeNumber];
        g_detail.end_bigZone = new int[chromosomeNumber];
        g_detail.chromosome_bigZone = new String[chromosomeNumber];
        g_detail.name_bigZone = new String[chromosomeNumber];
        int average = (posMax - posMin)/chromosomeNumber;

        for (int i=0;i<chromosomeNumber;i++){
            g_detail.start_bigZone[i] = i*average + posMin;
            g_detail.end_bigZone[i] = g_detail.start_bigZone[i]+average;
            if (i!=22){
                g_detail.chromosome_bigZone[i] = String.format("chr%d",i+1);
                g_detail.name_bigZone[i] = String.format("BG000%d",i+1);
            }else {
                g_detail.chromosome_bigZone[i] = String.format("chr%s","X");
                g_detail.name_bigZone[i] = String.format("BG000%s","X");
            }

        }

        //随机分配起始和终止位点
        number = 0;
        int[][] startAndEndPoint = new int[chromosomeNumber][];
        for (int i=0;i<chromosomeNumber;i++){
            startAndEndPoint[i] = new int[2*genesPerChrom[i]];
            startAndEndPoint[i] = RandomGen.randomCommon(posMin,posMax,2*genesPerChrom[i]);
            Arrays.sort(startAndEndPoint[i]);
        }

        for (int i=0;i<chromosomeNumber;i++){
            for (int j=0;j<startAndEndPoint[i].length;j++){
                if (j%2==0){
                    start[number] = startAndEndPoint[i][j];
                }else {
                    end[number] = startAndEndPoint[i][j];
                    number++;
                }
            }
        }
    }


    /*
     * 模拟数据（每种染色体的基因小分区数量等分，小分区长度为markers对应的一个位点的长度）
     * basicNumber:基础流水号
     * chromosomeNumber:染色体数目
     * totalNumber:基因总数
     * posMin/posMax:位点范围(左闭右开，左边0的时候则是开)
     *
     * */
    public void simulateEqually(String basicNumber,int chromosomeNumber,int totalNumber,int posMin,int posMax){
        String serial_number; //流水号
        order = new int[totalNumber];
        ensembl_gene_id = new String[totalNumber];
        associated_gene_name = new String[totalNumber];
        start = new int[totalNumber];
        end = new int[totalNumber];
        chromosome = new String[totalNumber];
        g_detail = new G_Detail();


        if (chromosomeNumber<1 && chromosomeNumber >23){
            System.out.println("染色体数目最多为23对，最少为1对");
        }

        if (totalNumber%chromosomeNumber!=0){
            System.out.println("基因数目没法等分，请重新设置染色体数目或基因总数。");
        }

        //赋予totalNumber个流水号
        for (int i=0;i<totalNumber;i++){
            ensembl_gene_id[i] = "NA";
            order[i] = i+1;
            serial_number = String.valueOf(i+1);
            serial_number = basicNumber.substring(0, basicNumber.length()-serial_number.length())+serial_number; //将序号和流水基础号组合
            associated_gene_name[i] = serial_number;
        }

        //赋予染色体，某个种类的染色体个数等分
        g_detail.chromosomeNumber = chromosomeNumber;

        int[] genesPerChrom = new int[chromosomeNumber];
//        int genesMaxNumber = 2*totalNumber/chromosomeNumber;  //基因上限，避免死循环
//        do {
//            genesPerChrom = RandomGen.randomSpliting(chromosomeNumber,totalNumber,genesMaxNumber);
//        }while (ArrayUtils.contains(genesPerChrom,1) || ArrayUtils.contains(genesPerChrom,2)); //保证每种染色体的标记个数不至于太少
        for (int i=0;i<chromosomeNumber;i++){
            genesPerChrom[i] = totalNumber/chromosomeNumber;
        }



        int number = 0;
        for (int i=0;i<chromosomeNumber;i++){
            for (int j=0;j<genesPerChrom[i];j++){
                if (i!=22){
                    chromosome[number++] = String.valueOf(i+1);
                }else {
                    chromosome[number++] = "X";
                }
            }
        }

        //分配大分区的始末位点，染色体，这里用等分的方式
        g_detail.posMin = posMin;
        g_detail.posMax = posMax;
        g_detail.start_bigZone = new int[chromosomeNumber];
        g_detail.end_bigZone = new int[chromosomeNumber];
        g_detail.chromosome_bigZone = new String[chromosomeNumber];
        g_detail.name_bigZone = new String[chromosomeNumber];
        int average = (posMax - posMin)/chromosomeNumber;

        for (int i=0;i<chromosomeNumber;i++){
            g_detail.start_bigZone[i] = i*average + posMin;
            g_detail.end_bigZone[i] = g_detail.start_bigZone[i]+average;
            if (i!=22){
                g_detail.chromosome_bigZone[i] = String.format("chr%d",i+1);
                g_detail.name_bigZone[i] = String.format("BG000%d",i+1);
            }else {
                g_detail.chromosome_bigZone[i] = String.format("chr%s","X");
                g_detail.name_bigZone[i] = String.format("BG000%s","X");
            }

        }

        //等分分配起始和终止位点，仅有一个点
        number = 0;
        int[][] startAndEndPoint = new int[chromosomeNumber][];
        for (int i=0;i<chromosomeNumber;i++){
            startAndEndPoint[i] = new int[genesPerChrom[i]];
            //startAndEndPoint[i] = RandomGen.randomCommon(posMin,posMax,2*genesPerChrom[i]);
            startAndEndPoint[i] = RandomGen.equalCommon(posMin,posMax,genesPerChrom[i]);
            Arrays.sort(startAndEndPoint[i]);
        }

        for (int i=0;i<chromosomeNumber;i++){
            for (int j=0;j<startAndEndPoint[i].length;j++){
                    start[number] = startAndEndPoint[i][j];
                    end[number] = startAndEndPoint[i][j];
                    number++;
            }
        }
    }
}
